package com.ilink.ilinkuser.service.impl;


import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ilink.ilinkcommon.config.JwtProperties;
import com.ilink.ilinkcommon.domain.R;
import com.ilink.ilinkcommon.domain.User;
import com.ilink.ilinkcommon.domain.DTO.UserAuthenticationRequest;
import com.ilink.ilinkcommon.domain.PO.userService.UserProjectParticipation;
import com.ilink.ilinkcommon.domain.VO.UserAuthenticationResponse;
import com.ilink.ilinkcommon.exception.UnauthorizedException;
import com.ilink.ilinkcommon.service.oss.OssService;
import com.ilink.ilinkcommon.utils.JwtTokenProvider;
import com.ilink.ilinkcommon.utils.SnowflakeIdGenerator;
import com.ilink.ilinkuser.domain.VO.UserMetaResponse;
import com.ilink.ilinkuser.entity.AiXSceneAuthorUser;
import com.ilink.ilinkuser.entity.AiXSceneBaseUser;
import com.ilink.ilinkuser.mapper.AiXSceneAuthorUserMapper;
import com.ilink.ilinkuser.mapper.AiXSceneBaseUserMapper;
import com.ilink.ilinkuser.mapper.UserMapper;
import com.ilink.ilinkuser.mapper.UserProjectParticipationMapper;
import com.ilink.ilinkuser.service.UserMessageExportService;
import com.ilink.ilinkuser.service.UserService;

import lombok.extern.slf4j.Slf4j;


@Slf4j
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserProjectParticipationMapper userProjectParticipationMapper;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private OssService ossService;

    @Autowired
    private UserMessageExportService userMessageExportService;

    @Autowired
    private AiXSceneBaseUserMapper aiXSceneBaseUserMapper;

    @Autowired
    private AiXSceneAuthorUserMapper aiXSceneAuthorUserMapper;

    @Lazy
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // Redis key前缀
    private static final String AUTH_CODE_PREFIX = "oauth:auth_code:";
    // 授权码过期时间(2分钟)
    private static final long AUTH_CODE_EXPIRE = 120;

    /**
     * 正则-密码强度-基础要求, 必须字母+数字，长度检测不在此处
     */
    public static final String REGEX_PASSWORD_STRENGTH_BASIC = "^(?![0-9]+$)(?![a-zA-Z]+$).{1,}$";
    /**
     * 正则-密码强度-至少一位大写字母
     */
    public static final String REGEX_PASSWORD_STRENGTH_UPPER_CHAR = "^(?=.*[A-Z]).+$";
    /**
     * 正则-密码强度-至少一位符号
     */
    public static final String REGEX_PASSWORD_STRENGTH_CHARS = "^(?=.*[`~!@#$%^&*()_\\-+=<>?:\"{}|,./;'\\[\\]·~！@#￥%……&*（）——\\-+={}|《》？：“”【】、；‘'，。、]).+$";

    /**
     * 根据用户名查询用户信息
     *
     * @param username
     * @return org.springframework.security.core.userdetails.UserDetails
     * @author liuzheng
     * @create 2024-07-27
     **/
    @Override
    public User loadUserByUsername(String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        User user = userMapper.selectOne(queryWrapper.last("limit 1"));
        if (user == null) {
            return null;
        }
        return user;
    }

    @Override
    public boolean checkUsernameAndPassword(String username, String password) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername, username);
        User user = userMapper.selectOne(lambdaQueryWrapper.last("limit 1"));
        if (user == null) {
            return false;
        }
        return passwordEncoder.matches(password, user.getPassword());
    }


    @Override
    public User loadUserByUserId(String userId) {
        String cleanUserId = userId.replace("\"", "");
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", cleanUserId);
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            return null;
        }
        return user;
    }


    /**
     * 创建新用户
     *
     * @param user
     * @return void
     * @author liuzheng
     * @create 2024-07-27
     **/
    @Override
    public void createUser(User user) {
        User newUser = (User) user;
        newUser.setPassword(passwordEncoder.encode(newUser.getPassword()));
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 10);
        String timestamp = String.valueOf(System.currentTimeMillis()).substring(5); // 获取时间戳的后8位
        String userId = uuid + timestamp;
        newUser.setUserId(userId);
        userMapper.insert(newUser);
    }


    @Override
    public void changePassword(String userId, String oldPassword, String newPassword) {
        // Implement password change logic if required
        User user = userMapper.selectById(userId);
        Assert.notNull(user, "User not found");
        if (passwordEncoder.matches(oldPassword, user.getPassword())) {
            user.setPassword(passwordEncoder.encode(newPassword));
            userMapper.updateById(user);
        } else {
            throw new IllegalArgumentException("Old password is incorrect");
        }
    }

    @Override
    public boolean userExists(String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        return userMapper.selectCount(queryWrapper) > 0;
    }


    /**
     * @return java.lang.String
     * @Author Black Curry
     * @Description 校验密码强度，返回提示信息，只有范围TRUE字符串时才表示密码强度合格
     * @Date 15:23 2024/9/26
     * @Param [password]
     **/
    @Override
    public String checkPasswordStrength(String password) {
        //  长度检查 必须大于等于8位
        if (password.length() < 8) {
            return "密码长度必须大于等于8位";
        }

        //密码检查，字母和数字、大写字符、特殊符号
        boolean basicMatches = Pattern.compile(REGEX_PASSWORD_STRENGTH_BASIC).matcher(password)
            .matches();
        boolean upperCharMatches = Pattern.compile(REGEX_PASSWORD_STRENGTH_UPPER_CHAR)
            .matcher(password).matches();
        boolean charsMatches = Pattern.compile(REGEX_PASSWORD_STRENGTH_CHARS).matcher(password)
            .matches();

        //  缺少一项就追加一项提醒
        String res = "";
        if (!basicMatches) {
            res += "密码必须包含字母和数字";
        }
        if (!upperCharMatches) {
            res += "密码必须包含大写字母";
        }
        if (!upperCharMatches) {
            res += "密码必须包含特殊字符";
        }

        if (!res.isBlank()) {
            return res;
        }

        return "TRUE";
    }

    @Override
    public boolean updateUserMetaByFile(MultipartFile file) {
        //csv覆盖用户元信息
//        try(Reader reader = new InputStreamReader(file.getInputStream())){
//            // 使用 OpenCSV 解析 CSV 文件
//            CSVReader csvReader = new CSVReader(reader);
//            List<String[]> csvData = csvReader.readAll();
//            // 跳过第一行标题
//            csvData.remove(0);
//            // 使用 Map.ofEntries 进行初始化映射
//            Map<Integer, String> fieldMapping = Map.ofEntries(
//                Map.entry(0, "realname"),            // 姓名
//                Map.entry(1, "school"),              // 就读学校
//                Map.entry(2, "college"),             // 所属学院
//                Map.entry(3, "studentId"),           // 学号
//                Map.entry(4, "phoneNumber"),         // 手机号
//                Map.entry(5, "email"),               // 邮箱
//                Map.entry(6, "participationType"),   // 参与方式
//                Map.entry(7, "campus"),              // 所属校区
//                Map.entry(8, "studentStatus"),       // 在校生身份
//                Map.entry(9, "enrollmentYear"),      // 入学年份
//                Map.entry(10, "projectStatus"),      // 项目情况
//                Map.entry(11, "projectType"),        // 项目类型
//                Map.entry(12, "projectName")         // 项目名称
//            );
//
//            for (String[] row : csvData) {
//                // 遍历映射字典，根据列索引逐个检查并选择覆盖用户的值
//                for (Map.Entry<Integer, String> entry : fieldMapping.entrySet()) {
//                    Integer columnIndex = entry.getKey();   // CSV 列索引
//                    String fieldName = entry.getValue();    // userDTO 中对应的字段名
//
//                    //查询对应用户ID
//                    User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(
//                        User::getSchoolId, row[3]
//                    ).last("limit 1"));
//
//                    UserProjectParticipation userProjectParticipation = userProjectParticipationMapper.selectOne(new LambdaQueryWrapper<UserProjectParticipation>().eq(UserProjectParticipation::getUserId, user.getUserId()).last("limit 1"));
//                    if (row[columnIndex] != null && !row[columnIndex].trim().isEmpty()) {
//                        if (columnIndex <= 9 && columnIndex != 3) {
//                            if (fieldName.equals("enrollmentYear")) {
//                                user.setEnrollmentYear(row[columnIndex]);
//                            } else if (fieldName.equals("studentStatus")) {
//                                user.setStudentStatus(row[columnIndex]);
//                            } else if (fieldName.equals("campus")) {
//                                user.setUserCampus(row[columnIndex]);
//                            } else if (fieldName.equals("projectStatus")) {
//                                userProjectParticipation.setProjectStatus(row[columnIndex]);
//                            }
//
//                        }
//
//                        // 使用反射机制动态设置 userDTO 的字段值
//                        Field field = UserAuthenticationRequest.class.getDeclaredField(fieldName);
//                        field.setAccessible(true);
//                        field.set(userDTO, row[columnIndex].trim()); // 设置值
//                    }
//                }
//            }
//            return true;
//        }catch (IOException e) {
//            log.error("文件处理失败: " + e.getMessage());
//            throw new RuntimeException("文件处理失败: " + e.getMessage());
//        } catch (CsvException e) {
//            log.error("文件处理失败: " + e.getMessage());
//            throw new RuntimeException(e);
//        }
        return false;
    }

    //查看用户的信息数据
    @Override
    public UserMetaResponse getUserMetaById(String userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            return null;
        }
        //  note: 只能展示可以暴露给前端的属性
        UserMetaResponse response = new UserMetaResponse();
        response.setUserId(userId);
        response.setNickname(user.getUsername());
        response.setSchoolName(user.getSchoolName());
        response.setEmail(user.getEmail());
        response.setSchoolId(user.getSchoolId());
        response.setUserIntroduction(user.getUserIntroduction());
        response.setUserType(user.getUserType());
        if (user.getUserImage() != null) {
            String ImageUrl = ossService.getFileUrl(user.getUserImage());
            if (ImageUrl != null) {
                response.setUserImage(ImageUrl);
            } else {
                log.error("用户{}的ImageUrl is null", userId);
            }
        }
//        response.setUserImage(user.getUserImage());
        response.setUserCollege(user.getUserCollege());
        response.setRealname(user.getRealname());
        response.setSex(user.getSex());
//        response.setUserStudentNumber(user.getUserStudentNumber());
        response.setUserGrade(user.getUserGrade());
        response.setUserMajor(user.getUserMajor());
        response.setUserMobile(user.getUserMobile());
        if (user.getUserCover() != null) {
            String CoverUrl = ossService.getFileUrl(user.getUserCover());
            if (CoverUrl != null) {
                response.setUserCover(CoverUrl);
            } else {
                log.error("用户{}的CoverUrl is null", userId);
            }
        }
        response.setLastLoginAt(user.getLastLoginAt());
//        response.setUserCover(user.getUserCover());
        return response;
    }

    //获取用户的认证信息
    @Override
    public UserAuthenticationResponse getUserAuthenticationById(String userId) {
        UserAuthenticationResponse response = new UserAuthenticationResponse();

        //1.从用户表中获取信息
        User user = userMapper.selectById(userId);
        if (user == null) {
            return null;
        }
        if (!userMessageExportService.syncUserMessage(user)){
            log.error("通过用户统计数据更新覆盖用户信息失败");
        }
        //用户个人信息
        if (user.getUserImage() != null) {
            String ImageUrl = ossService.getFileUrl(user.getUserImage());
            if (ImageUrl != null) {
                response.setUserImage(ImageUrl);
            } else {
                log.error("用户{}的ImageUrl is null", userId);
            }
        }
        if (user.getUserCover() != null) {
            String CoverUrl = ossService.getFileUrl(user.getUserCover());
            if (CoverUrl != null) {
                response.setUserCover(CoverUrl);
            } else {
                log.error("用户{}的CoverUrl is null", userId);
            }
        }
        response.setNickName(user.getUsername());
        response.setSex(user.getSex());
        response.setUserIntroduction(user.getUserIntroduction());

        //  note: 只能展示可以暴露给前端的属性
        response.setRealName(user.getRealname());
        response.setSchool(user.getSchoolName());
        response.setCollege(user.getUserCollege());
        response.setMajor(user.getUserMajor());
        response.setStudentId(user.getSchoolId());
        response.setPhoneNumber(user.getUserMobile());
        response.setEmail(user.getEmail());

//        if (!user.getSchoolName().contains("北京邮电大学"))
        response.setCampus(user.getUserCampus());
        response.setStudentStatus(user.getStudentStatus());
        response.setEnrollmentYear(user.getEnrollmentYear());


        //2.从用户项目表中获取项目关联信息
        UserProjectParticipation userProjectParticipation = userProjectParticipationMapper.selectOne(new LambdaQueryWrapper<UserProjectParticipation>().eq(UserProjectParticipation::getUserId, userId));
        if (userProjectParticipation != null) {
            response.setParticipationType(userProjectParticipation.getParticipationType());
            response.setProjectStatus(userProjectParticipation.getProjectStatus());
            response.setProjectType(userProjectParticipation.getProjectType());
            response.setProjectName(userProjectParticipation.getProjectName());
        }
        return response;
    }

    //更新用户信息数据
    @Override
    public boolean updateUserMetaById(String userId, UserAuthenticationRequest userMetaResponse) {
        User user = userMapper.selectById(userId);
        //写入用户个人信息:这里不更新封面和头像
        user.setNickname(userMetaResponse.getNickName());
        user.setSex(userMetaResponse.getSex());
        user.setUserIntroduction(userMetaResponse.getUserIntroduction());

        //写入用户认证信息
        user.setRealname(userMetaResponse.getRealName());
        user.setSchoolName(userMetaResponse.getSchool());
        user.setUserCollege(userMetaResponse.getCollege());
        user.setUserMajor(userMetaResponse.getMajor());
        user.setSchoolId(userMetaResponse.getStudentId());
        user.setUserMobile(userMetaResponse.getPhoneNumber());
        user.setEmail(userMetaResponse.getEmail());
        user.setUserCampus(userMetaResponse.getCampus());
        user.setStudentStatus(userMetaResponse.getStudentStatus());
        user.setEnrollmentYear(userMetaResponse.getEnrollmentYear());
        //写入项目参与情况
        UserProjectParticipation userProjectParticipation = userProjectParticipationMapper.selectOne(new LambdaQueryWrapper<UserProjectParticipation>().eq(UserProjectParticipation::getUserId, userId).last("limit 1"));
        if (userProjectParticipation != null) {
            userProjectParticipation.setParticipationType(userMetaResponse.getParticipationType());
            userProjectParticipation.setProjectStatus(userMetaResponse.getProjectStatus());
            userProjectParticipation.setProjectType(userMetaResponse.getProjectType());
            userProjectParticipation.setProjectName(userMetaResponse.getProjectName());
            userProjectParticipationMapper.updateById(userProjectParticipation);
        }else{
            //还没有参与项目的记录
            userProjectParticipation = new UserProjectParticipation();
            userProjectParticipation.setUserId(userId);
            userProjectParticipation.setProjectName(userMetaResponse.getProjectName());
            userProjectParticipation.setParticipationType(userMetaResponse.getParticipationType());
            userProjectParticipation.setProjectStatus(userMetaResponse.getProjectStatus());
            userProjectParticipation.setProjectType(userMetaResponse.getProjectType());
            userProjectParticipationMapper.insert(userProjectParticipation);
        }
        int result = userMapper.updateById(user);
        return result > 0;
    }

    @Override
    //更新用户封面和头像
    public R updateUserImageById(User user, MultipartFile userCover, MultipartFile userImage) {
        try {
            log.info("user:{}", user);
            String Cover_path;
            String image_path;
            //不为空时上传封面和用户头像
            if (userCover != null) {
                Cover_path = uploadUserImage(userCover, user.getUserId());
                if (Cover_path != null) {
                    user.setUserCover(Cover_path);
                }
            }
            if (userImage != null) {
                image_path = uploadUserImage(userImage, user.getUserId());
                if (image_path != null) {
                    user.setUserImage(image_path);
                }
            }
            boolean isUpdated = userMapper.updateById(user) > 0;
            if (isUpdated) {
                return R.ok("修改用户图片成功", user.getUserId());
            } else {
                log.error("Failed to update user meta for {}", user.getUserId());
                //撤回对图片的导入
                //待增加

                return R.error("User not found or update failed");
            }
        } catch (UnauthorizedException e) {
            return R.error(e);
        }

    }

    @Override
    //上传用户照片
    public String uploadUserImage(MultipartFile file, String userId) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(3, 1);
        // 获取原始文件名
        String originalFilename = file.getOriginalFilename();

        // 获取文件扩展名
        String fileExtension = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        } else {
            log.error("文件解析扩展名出现错误：" + originalFilename);
            return null;
        }
        Long id =idGenerator.nextId();
        boolean uploadCover = ossService.uploadFile(file, "image/" + userId + "/",
            id + fileExtension);
        if (!uploadCover) {
            log.info("用户{}的图片上传失败", userId);
            return null;
        } else {
            //图片路径
            return "image/" + userId + "/" + id + fileExtension;
        }
    }

    @Override
    public Map<String, Object> generateTokens(String userId) {
        Map<String, String> accessTokenData = new HashMap<>();
        accessTokenData.put("sub", userId);
        accessTokenData.put("type", "access");
        long accessTokenExpiresIn = jwtProperties.getTokenTTL();
        String accessToken = jwtTokenProvider.createToken(accessTokenData, accessTokenExpiresIn);

        Map<String, String> refreshTokenData = new HashMap<>();
        refreshTokenData.put("sub", userId);
        refreshTokenData.put("type", "refresh");
        long refreshTokenExpiresIn = jwtProperties.getRefreshTTL();
        String refreshToken = jwtTokenProvider.createToken(refreshTokenData, refreshTokenExpiresIn);

        Map<String, Object> tokens = new HashMap<>();
        tokens.put("access_token", accessToken);
        tokens.put("refresh_token", refreshToken);
        tokens.put("token_type", "bearer");

        return tokens;
    }

    @Override
    public void setTokenCookies(HttpServletResponse response, Map<String, Object> tokens) {
        String accessToken = (String) tokens.get("access_token");
        String refreshToken = (String) tokens.get("refresh_token");

        Cookie accessCookie = new Cookie("access_token_lf", accessToken);
        accessCookie.setPath("/");
        accessCookie.setHttpOnly(false);
        accessCookie.setSecure(false);
        accessCookie.setMaxAge(Math.toIntExact(jwtProperties.getTokenTTL()));
        response.addCookie(accessCookie);

        Cookie refreshCookie = new Cookie("refresh_token_lf", refreshToken);
        refreshCookie.setPath("/");
        refreshCookie.setHttpOnly(false);
        refreshCookie.setSecure(false);
        refreshCookie.setMaxAge(Math.toIntExact(jwtProperties.getRefreshTTL()));
        response.addCookie(refreshCookie);
    }

    @Override
    public List<User> searchUserBySchoolIdAndName(String query) {
        try {
            LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
            if(query.length()>=8){
                userLambdaQueryWrapper =  userLambdaQueryWrapper.like(User::getSchoolId,query);
            } else {
                userLambdaQueryWrapper =  userLambdaQueryWrapper.eq(User::getSchoolId,query);
            }
            return userMapper.selectList(userLambdaQueryWrapper
                .or()
                .like(User::getRealname, query)); // 部分匹配
        } catch (Exception e) {
            log.error("搜索用户时发生错误: {}", e.getMessage());
            return Collections.emptyList(); // 返回空列表以避免抛出异常
        }
    }

    @Override
    public List<User> searchUserByRealName(String query) {
        try {
            return userMapper.selectList(new LambdaQueryWrapper<User>().like(User::getRealname, query));
        } catch (Exception e) {
            log.error("搜索用户时发生错误: {}", e.getMessage());
            return Collections.emptyList(); // 返回空列表以避免抛出异常
        }
    }

    /**
     * @Author ZhangBo
     * @Description 根据用户id和SceneId，获取用户是否具有创建、查看、编辑场景权限
     * @Date 15:43 2025/1/18
     * @Param
     * @return
     **/
    @Override
    public Map<String, Boolean> checkUserScenePermission(String userId, Long sceneId) {
        Map<String, Boolean> permissions = new HashMap<>();
        permissions.put("create", false);
        permissions.put("view", false);
        permissions.put("edit", false);

        try {
            // 判断是否是教师
            User userDetail = userMapper.selectById(userId);
            if (userDetail == null) {
                return permissions;
            }

            String userType = userDetail.getUserType();
            // 判断是否是教师
            boolean isTeacher = java.util.Arrays.asList("BIAdmin", "L0101", "L0107", "L0108", "L0109").contains(userType);
            permissions.put("create", isTeacher); // 只有教师可以创建

            if (sceneId != null && !sceneId.equals("0")) {
                // 判断是否是超级管理员
                boolean isSuperAdmin = "BIAdmin".equals(userType);

                // 判断是否是出品人
                boolean isAuthor = false;
                try {
                    List<String> authorIds = aiXSceneAuthorUserMapper.selectList(
                        new LambdaQueryWrapper<AiXSceneAuthorUser>()
                            .eq(AiXSceneAuthorUser::getSceneId, sceneId)
                    ).stream()
                        .map(AiXSceneAuthorUser::getUserId)
                        .collect(java.util.stream.Collectors.toList());
                    isAuthor = authorIds.contains(userId);
                } catch (Exception e) {
                    log.error("查询出品人信息时发生错误: {}", e.getMessage());
                }

                // 超级管理员和出品人始终具有查看、编辑权限
                if (isSuperAdmin || isAuthor) {
                    permissions.put("view", true);
                    permissions.put("edit", true);
                }

                // 如果根据sceneId查询到场景的isPublished为true，则具有查看权限
                AiXSceneBaseUser scene = aiXSceneBaseUserMapper.selectById(sceneId);
                if (scene != null && scene.getIsPublish()) {
                    permissions.put("view", true);
                }
            }
            log.info("权限获取",permissions);
            return permissions;

        } catch (Exception e) {
            log.error("检查用户场景权限时发生错误: {}", e.getMessage());
            return permissions;
        }
    }

    /**
     * 生成授权码并关联用户ID
     * @param clientId 客户端ID
     * @param scope 授权范围
     * @param state 状态参数
     * @param userId 用户ID
     * @return 授权码
     */
    @Override
    public String generateAuthorizationCode(String clientId, String scope, String state, String userId) {
        try {
            // 生成授权码
            String authCode = UUID.randomUUID().toString().replace("-", "");

            // 构建授权信息
            Map<String, String> authInfo = new HashMap<>();
            authInfo.put("clientId", clientId);
            authInfo.put("scope", scope);
            authInfo.put("state", state);
            authInfo.put("userId", userId); // 直接存储userId
            authInfo.put("createdAt", String.valueOf(System.currentTimeMillis()));

            // 存储到Redis并设置过期时间
            String key = AUTH_CODE_PREFIX + authCode;
            stringRedisTemplate.opsForHash().putAll(key, authInfo);
            stringRedisTemplate.expire(key, AUTH_CODE_EXPIRE, TimeUnit.SECONDS);

            log.info("Generated auth code for user: {}, client: {}", userId, clientId);
            return authCode;

        } catch (Exception e) {
            log.error("Failed to generate authorization code", e);
            throw new RuntimeException("生成授权码失败");
        }
    }

    /**
     * 验证授权码
     * @param code 授权码
     * @return 是否有效
     */
    @Override
    public boolean validateAuthorizationCode(String code) {
        if (code == null || code.isBlank()) {
            return false;
        }

        try {
            String key = AUTH_CODE_PREFIX + code;

            // 检查授权码是否存在
            Boolean exists = stringRedisTemplate.hasKey(key);
            if (!Boolean.TRUE.equals(exists)) {
                return false;
            }

            // 获取授权信息
            Map<Object, Object> authInfo = stringRedisTemplate.opsForHash().entries(key);
            if (authInfo.isEmpty()) {
                return false;
            }

            // 验证创建时间,检查是否过期(双重检查,虽然Redis自己会过期)
            String createdAtStr = (String) authInfo.get("createdAt");
            if (createdAtStr != null) {
                long createdAt = Long.parseLong(createdAtStr);
                long now = System.currentTimeMillis();
                if (now - createdAt > AUTH_CODE_EXPIRE * 1000) {
                    // 手动删除过期的授权码
                    stringRedisTemplate.delete(key);
                    return false;
                }
            }

            // 验证成功后立即删除授权码,防止重放攻击
            stringRedisTemplate.delete(key);

            // 将授权信息暂存到另一个短期key中,供后续getUserIdFromAuthCode使用
            String tempKey = AUTH_CODE_PREFIX + "temp:" + code;
            stringRedisTemplate.opsForHash().putAll(tempKey, authInfo);
            stringRedisTemplate.expire(tempKey, 30, TimeUnit.SECONDS); // 给30秒的处理时间窗口

            return true;
        } catch (Exception e) {
            log.error("Failed to validate authorization code", e);
            return false;
        }
    }

    /**
     * 从授权码获取用户ID
     * @param code 授权码
     * @return 用户ID
     */
    @Override
    public String getUserIdFromAuthCode(String code) {
        if (code == null || code.isBlank()) {
            throw new UnauthorizedException("授权码不能为空");
        }

        try {
            // 尝试从临时存储中获取授权信息
            String tempKey = AUTH_CODE_PREFIX + "temp:" + code;
            Map<Object, Object> authInfo = stringRedisTemplate.opsForHash().entries(tempKey);

            if (authInfo.isEmpty()) {
                throw new UnauthorizedException("无效的授权码或授权码已过期");
            }

            // 获取用户ID
            String userId = (String) authInfo.get("userId");
            if (userId == null || userId.isBlank()) {
                throw new UnauthorizedException("授权码中未包含用户信息");
            }

            // 删除临时存储的授权信息
            stringRedisTemplate.delete(tempKey);

            log.info("Retrieved user ID from auth code: {}", userId);
            return userId;

        } catch (Exception e) {
            log.error("Failed to get user ID from auth code", e);
            throw new RuntimeException("获取用户信息失败");
        }
    }
}
